/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {
  gravity,
  SensorTypes,
  setUpdateIntervalForType,
} from 'react-native-sensors';
import { Subscription } from 'rxjs';

export interface GravityChangedListener {
  (orientation: number): void;
}

export class SensorUtil {
  private static instance: SensorUtil;
  private rotation = 0;
  private subscription: Subscription | null = null;
  private gravityChangedListener: GravityChangedListener | undefined =
    undefined;

  private constructor() {}

  public static getInstance(): SensorUtil {
    if (!SensorUtil.instance) {
      SensorUtil.instance = new SensorUtil();
    }
    return SensorUtil.instance;
  }

  /**
   * 添加重力变化监听回调
   * @param gravityChangedListener 回调函数
   */
  public addGravityChangeListener(
    gravityChangedListener: GravityChangedListener
  ): void {
    this.gravityChangedListener = gravityChangedListener;
  }

  /**
   * 移除重力变化监听回调
   */
  public removeGravityChangeListener(): void {
    this.gravityChangedListener = undefined;
  }

  public subscribe(): void {
    if (this.subscription) {
      console.warn('Already subscribed to gravity sensor.');
      return;
    }
    setUpdateIntervalForType(SensorTypes.gravity, 200000000);
    this.subscription = gravity.subscribe(({ x, y, z, timestamp }) => {
      let degree = this.calDegree(x, y, z);
      if (degree === -1) {
        return;
      }
      let isOrientation = true;
      if (degree >= 0 && (degree <= 30 || degree >= 330)) {
        this.rotation = 0; // 竖向
      } else if (degree >= 60 && degree <= 120) {
        this.rotation = 1; // 横向 手机竖屏向右旋转
      } else if (degree >= 150 && degree <= 210) {
        this.rotation = 2; // 反竖向
      } else if (degree >= 240 && degree <= 300) {
        this.rotation = 3; // 反横向 手机竖屏向左旋转
      } else {
        isOrientation = false;
      }

      if (isOrientation && this.gravityChangedListener) {
        this.gravityChangedListener(this.rotation);
      }
    });
  }

  public unsubscribe(): void {
    if (this.subscription) {
      this.subscription.unsubscribe(); // 取消订阅
      this.subscription = null; // 清空订阅对象
    } else {
      console.warn('No active subscription to gravity sensor.');
    }
  }

  /**
   * 根据重力获取手机旋转方向
   */
  public getRotation(): number {
    return this.rotation;
  }

  private calDegree(x: number, y: number, z: number): number {
    let degree: number = -1;
    if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(x)) {
      return degree;
    }
    if ((x * x + y * y) * 3 < z * z) {
      return degree;
    }
    degree = 90 - Number(Math.round((Math.atan2(y, -x) / Math.PI) * 180));
    return degree >= 0 ? degree % 360 : (degree % 360) + 360;
  }
}
